package sg.edu.nus.iss.billing.template;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import sg.edu.nus.iss.billing.entity.Bill;
import sg.edu.nus.iss.billing.entity.ChargeComponent;
import sg.edu.nus.iss.billing.entity.PaymentHistory;
import sg.edu.nus.iss.billing.exception.TemplateEngineException;
import sg.edu.nus.iss.billing.localization.MessageKeyManager;

/**
 * @author Daniel
 *
 */
public class OneTelcoParseActionProcessor extends BasicParseActionProcessor {
	
	private Bill bill;
	private DecimalFormat decimalFormatter;
	private DateFormat dateFormat;
	
	public OneTelcoParseActionProcessor(BillingTemplate saTemplate, Bill bill) throws TemplateEngineException {
		super(saTemplate);
		this.bill = bill;
		//if (saTemplate.getTemplateFileName().equals("billing.html")) {
		//addParseAction(new BasicParseAction("\\$\\{getPreviousPayment\\}", "$35.5"));
			generateNormalTemplate();
		//} else {
			//not yet defined but it should be supporting different template processing.
			//different template should use different parse strategy
		//}
	}
	
	private void generateNormalTemplate() throws TemplateEngineException {
		try {
			decimalFormatter = new DecimalFormat(MessageKeyManager.getMessage("template.decimalFormat"));
			dateFormat = new SimpleDateFormat(MessageKeyManager.getMessage("template.dateFormat"));
			addParseActionList(ReflectionParseActionsFactory.generateParseListForStringField(bill));
			addParseActionList(ReflectionParseActionsFactory.generateParseListForDateField(bill, dateFormat));
			addParseActionList(ReflectionParseActionsFactory.generateParseListForBigDecimalField(bill, decimalFormatter));
			addParseAction(new BasicParseAction("\\$\\{getCustomerName\\}", bill.getClonedCustomer().getName()));
			addParseAction(new AddressParseAction("\\$\\{getCustomerBillingAddress\\}", bill.getClonedCustomer().getBillingAddress()));
			addParseAction(new BasicParseAction("\\$\\{populateDynamicPaymentListing\\}", populateDynamicPaymentListing(bill)));
			addParseAction(new BasicParseAction("\\$\\{populateDynamicSummaryServiceSection\\}", populateDynamicSummaryServiceSection(bill)));
			addParseAction(new BasicParseAction("\\$\\{populateDynamicCurrentAccountDetails\\}", populateDynamicCurrentAccountDetails(bill)));
		} catch (Exception e) {
			throw new TemplateEngineException(e.getMessage(), e);
		}
	}
	
	private String populateDynamicCurrentAccountDetails(Bill bill) {
		Map<String, List<ChargeComponent>> chargeComponentMap = bill.getChargeComponentMap();
		StringBuffer sb = new StringBuffer();
		if (chargeComponentMap != null && chargeComponentMap.size() > 0) {
			Iterator<String> iter = bill.getChargeComponentMap().keySet().iterator();
			while (iter.hasNext()) {
				String chargeKey = iter.next();
				String [] chargeKeyArr = chargeKey.split("_");
				List<ChargeComponent> chargeComponentList = chargeComponentMap.get(chargeKey);
				
				if (chargeKeyArr.length == 3 && chargeKeyArr[1].equals("CTVSERVICE")) {
					//cableTV Subscription
					sb.append("<tr>");
					sb.append("<td colspan='4'>");
					sb.append("<b>" + chargeKeyArr[0] + "</b>");
					sb.append("</td>");
					sb.append("</tr>");
					
					sb.append("<tr>");
					sb.append("<td width='20%'>");
					ChargeComponent cc = getChargeComponentByChargeName("Subscription charges",chargeComponentList); 
					sb.append(cc.getChargeDescription());
					sb.append("</td>");
					sb.append("<td width='35%'>");
					sb.append("&nbsp;");
					sb.append("</td>");
					sb.append("<td width='20%'>");
					sb.append(decimalFormatter.format(cc.getChargeAmt()));
					sb.append("</td>");
					sb.append("<td width='25%'>");
					sb.append("&nbsp;");
					sb.append("</td>");
					sb.append("</tr>");
					
					for (int i=0; i < chargeComponentList.size(); i++) {
						ChargeComponent chargeComponent = chargeComponentList.get(i);
						if (Bill.GROUP_VAS_LINE.equals(chargeComponent.getChargeGroupKey())) {
							sb.append("<tr>");
							sb.append("<td width='20%'>");
							sb.append(chargeComponent.getChargeDescription());
							sb.append("</td>");
							sb.append("<td width='35%'>");
							sb.append("&nbsp;");
							sb.append("</td>");
							sb.append("<td width='20%'>");
							sb.append(decimalFormatter.format(chargeComponent.getChargeAmt()));
							sb.append("</td>");
							sb.append("<td width='25%'>");
							sb.append("&nbsp;");
							sb.append("</td>");
							sb.append("</tr>");
						}
					}
					
					ChargeComponent totalSubs = getChargeComponentByChargeName(Bill.SUBS_TOTAL, chargeComponentList);
					
					sb.append("<tr>");
					sb.append("<td width='20%'>");
					sb.append("&nbsp;");
					sb.append("</td>");
					sb.append("<td width='35%'>");
					sb.append("&nbsp;");
					sb.append("</td>");
					sb.append("<td width='20%'>");
					sb.append("&nbsp;");
					sb.append("</td>");
					sb.append("<td width='25%'>");
					sb.append("<b>" + decimalFormatter.format(totalSubs.getChargeAmt()) + "</b>");
					sb.append("</td>");
					sb.append("</tr>");
					
				} else {
					sb.append("<tr>");
					sb.append("<td colspan='4'>");
					sb.append("<b>" + chargeKeyArr[0] + "&nbsp;&nbsp;&nbsp;" + chargeKeyArr[2] + "</b>");
					sb.append("</td>");
					sb.append("</tr>");
					
					sb.append("<tr>");
					sb.append("<td colspan='4'>");
					sb.append("<i><b>Subscription Charges</b></i>");
					sb.append("</td>");
					sb.append("</tr>");
					
					sb.append("<tr>");
					sb.append("<td width='20%'>");
					ChargeComponent cc = getChargeComponentByChargeName("Line",chargeComponentList); 
					sb.append(cc.getChargeDescription());
					sb.append("</td>");
					sb.append("<td width='35%'>");
					sb.append("&nbsp;");
					sb.append("</td>");
					sb.append("<td width='20%'>");
					sb.append(decimalFormatter.format(cc.getChargeAmt()));
					sb.append("</td>");
					sb.append("<td width='25%'>");
					sb.append("&nbsp;");
					sb.append("</td>");
					sb.append("</tr>");
					
					for (int i=0; i < chargeComponentList.size(); i++) {
						ChargeComponent chargeComponent = chargeComponentList.get(i);
						if (Bill.GROUP_VAS_LINE.equals(chargeComponent.getChargeGroupKey())) {
							sb.append("<tr>");
							sb.append("<td width='20%'>");
							sb.append(chargeComponent.getChargeDescription());
							sb.append("</td>");
							sb.append("<td width='35%'>");
							sb.append("&nbsp;");
							sb.append("</td>");
							sb.append("<td width='20%'>");
							sb.append(decimalFormatter.format(chargeComponent.getChargeAmt()));
							sb.append("</td>");
							sb.append("<td width='25%'>");
							sb.append("&nbsp;");
							sb.append("</td>");
							sb.append("</tr>");
						}
					}
					
					sb.append("<tr>");
					sb.append("<td colspan='4'>");
					sb.append("<i><b>Usage Charges</b></i>");
					sb.append("</td>");
					sb.append("</tr>");
					
					for (int i=0; i < chargeComponentList.size(); i++) {
						ChargeComponent chargeComponent = chargeComponentList.get(i);
						if (Bill.GROUP_SUBS_USAGE.equals(chargeComponent.getChargeGroupKey())) {
							sb.append("<tr>");
							sb.append("<td width='20%'>");
							sb.append(chargeComponent.getChargeDescription());
							sb.append("</td>");
							sb.append("<td width='35%'>");
							sb.append("&nbsp;");
							sb.append("</td>");
							sb.append("<td width='20%'>");
							sb.append(decimalFormatter.format(chargeComponent.getChargeAmt()));
							sb.append("</td>");
							sb.append("<td width='25%'>");
							sb.append("&nbsp;");
							sb.append("</td>");
							sb.append("</tr>");
						}
					}
					
					ChargeComponent totalSubs = getChargeComponentByChargeName(Bill.SUBS_TOTAL, chargeComponentList);
					ChargeComponent totalUsage = getChargeComponentByChargeName(Bill.USAGE_TOTAL, chargeComponentList);
					
					BigDecimal totalBigDecimalAmt = totalSubs.getChargeAmt().add(totalUsage.getChargeAmt());
					sb.append("<tr>");
					sb.append("<td width='20%'>");
					sb.append("&nbsp;");
					sb.append("</td>");
					sb.append("<td width='35%'>");
					sb.append("&nbsp;");
					sb.append("</td>");
					sb.append("<td width='20%'>");
					sb.append("&nbsp;");
					sb.append("</td>");
					sb.append("<td width='25%'>");
					sb.append("<b>" + decimalFormatter.format(totalBigDecimalAmt) + "</b>");
					sb.append("</td>");
					sb.append("</tr>");
				}
				
			}
			
			//sb.append();
		}
		return sb.toString();
	}
	
	private ChargeComponent getChargeComponentByChargeName(String chargeName, List<ChargeComponent> ccList) {
		for (int i=0; i < ccList.size(); i++) {
			ChargeComponent cc = ccList.get(i);
			if (chargeName.equals(cc.getChargeDescription())) {
				return cc;
			}
		}
		return null;
	}
	
	private String populateDynamicSummaryServiceSection(Bill bill) {
		Map<String, List<ChargeComponent>> chargeComponentMap = bill.getChargeComponentMap();
		StringBuffer sb = new StringBuffer();
		if (chargeComponentMap != null && chargeComponentMap.size() > 0) {
			Iterator<String> iter = bill.getChargeComponentMap().keySet().iterator();
			while (iter.hasNext()) {
				String chargeKey = iter.next();
				String [] chargeKeyArr = chargeKey.split("_");
				
				sb.append("<tr>");
				sb.append("<td colspan='4'>");
				sb.append("<i><b>" + chargeKeyArr[0] + "</b></i>");
				sb.append("</td>");
				sb.append("</tr>");
				
				sb.append("<tr>");
				sb.append("<td width='20%' valign='top'>");
				sb.append("&nbsp;&nbsp;Subscription charges");
				sb.append("</td>");
				sb.append("<td width='35%' valign='top'>");
				sb.append("&nbsp;");
				sb.append("</td>");
				sb.append("<td width='20%' valign='top'>");
				List<ChargeComponent> chargeComponentList = chargeComponentMap.get(chargeKey);
				ChargeComponent cc = getChargeComponentByChargeName(Bill.SUBS_TOTAL,chargeComponentList);
				if (cc != null)
					sb.append(decimalFormatter.format(cc.getChargeAmt()));
				else
					sb.append(decimalFormatter.format(0));
				sb.append("</td>");
				sb.append("<td width='25%' valign='top'>");
				sb.append("&nbsp;");
				sb.append("</td>");
				sb.append("</tr>");
				
				sb.append("<tr>");
				sb.append("<td width='20%' valign='top'>");
				sb.append("&nbsp;&nbsp;Usage charges");
				sb.append("</td>");
				sb.append("<td width='35%' valign='top'>");
				sb.append("&nbsp;");
				sb.append("</td>");
				sb.append("<td width='20%' valign='top'>");
				cc = getChargeComponentByChargeName(Bill.USAGE_TOTAL,chargeComponentList);
				if (cc != null)
					sb.append(decimalFormatter.format(cc.getChargeAmt()));
				else
					sb.append(decimalFormatter.format(0));
				sb.append("</td>");
				sb.append("<td width='25%' valign='top'>");
				sb.append("&nbsp;");
				sb.append("</td>");
				sb.append("</tr>");
			}
		}
		return sb.toString();
	}
	
	private String populateDynamicPaymentListing(Bill bill) {
		List<PaymentHistory> pmentHistoryList = bill.getPaymentHistoryList();
		StringBuffer sb = new StringBuffer();
		BigDecimal partialPment = new BigDecimal(0);
		for (int i=0; i < pmentHistoryList.size(); i++) {
			PaymentHistory pmentHistory = pmentHistoryList.get(i);
			sb.append("<tr>");
			sb.append("	<td width='20%' valign='top'>");
			sb.append("		Payment received");
			sb.append("	</td>");
			sb.append("	<td width='35%' valign='top'>");
			sb.append(dateFormat.format(pmentHistory.getPaymentDate()));
			sb.append("	</td>");
			sb.append("	<td width='20%' valign='top'>");
			sb.append(decimalFormatter.format(pmentHistory.getPaymentAmt()));
			sb.append("	</td>");
			sb.append("	<td width='25%' valign='top'>");
			sb.append(decimalFormatter.format(partialPment.add(pmentHistory.getPaymentAmt())));
			sb.append("	</td>");
			sb.append("</tr>");
		}
		return sb.toString();
	}
	
	public void preProcess() throws TemplateEngineException {
		StringBuffer companyAddress = new StringBuffer();
		companyAddress.append(MessageKeyManager.getMessage("companyAddress.line1") + "<br>");
		companyAddress.append(MessageKeyManager.getMessage("companyAddress.line2") + "<br>");
		companyAddress.append(MessageKeyManager.getMessage("companyAddress.line3"));
		addParseAction(new BasicParseAction("\\$\\{getCompanyAddress\\}", companyAddress.toString()));
		addParseAction(new BasicParseAction("\\$\\{getHotlineNumber\\}", MessageKeyManager.getMessage("hotlineNumber")));
		addParseAction(new BasicParseAction("\\$\\{getCompanyEmail\\}", MessageKeyManager.getMessage("companyEmail")));
	}
	

}
